﻿using System;
using Belphegor.Composites;
using Belphegor.Dynamics;
using Belphegor.Helpers;
using Belphegor.Settings;
using Zeta;
using Zeta.Common.Helpers;
using Zeta.CommonBot;
using Zeta.Internals.Actors;
using Zeta.TreeSharp;
using Action = Zeta.TreeSharp.Action;

namespace Belphegor.Routines
{
    public class Barbarian
    {
        [Class(ActorClass.Barbarian)]
        [Behavior(BehaviorType.Buff)]
        public static Composite BarbarianBuffs()
        {
            return
                new PrioritySelector(

                    Common.CreateWaitForAttack(),

                    new SelfCast(SNOPower.Barbarian_WarCry, 
                        extra => (!ZetaDia.Me.HasBuff(SNOPower.Barbarian_WarCry) || BelphegorSettings.Instance.Barbarain.SpamWarCry) &&
                                    (PowerManager.CanCast(SNOPower.Barbarian_Sprint) || !ZetaDia.Me.IsInTown)),

                    new Decorator (ret => _sprintTimer.IsFinished && PowerManager.CanCast(SNOPower.Barbarian_Sprint) 
                       && !ZetaDia.Me.HasBuff(SNOPower.Barbarian_Sprint),
                        new Sequence(
                            new SelfCast(SNOPower.Barbarian_Sprint, extra => ZetaDia.Me.Movement.IsMoving),
                            new Action (ret => _sprintTimer.Reset())))
                );
        }

        [Class(ActorClass.Barbarian)]
        [Behavior(BehaviorType.Combat)]
        public static Composite BarbarianCombat()
        {
            return
                new PrioritySelector(ctx => CombatTargeting.Instance.FirstNpc,
                    new Decorator(ctx => ctx != null,
                        new PrioritySelector(
                            Common.CreateWaitForAttack(),

                            // Buff attack rate or get free!
                            new SelfCast(SNOPower.Barbarian_WrathOfTheBerserker,
                                extra => (Clusters.GetClusterCount(ZetaDia.Me, CombatTargeting.Instance.LastObjects, ClusterType.Radius, 12f) >= 6 ||
                                Unit.MeIncapacited)
                            ),

                            Common.CreateWaitWhileIncapacitated(),
                            Common.CreateUsePotion(),

                            // Defence low hp or many attackers.
                            new SelfCast(SNOPower.Barbarian_IgnorePain,
                                require => ZetaDia.Me.HitpointsCurrentPct <= BelphegorSettings.Instance.Barbarain.IgnorePainPct
                                    || Clusters.GetClusterCount(ZetaDia.Me, CombatTargeting.Instance.LastObjects, ClusterType.Radius, 12f) >= 6
                            ),

                            // Pull phase.
                            new Decorator(ctx => ctx != null && ((DiaUnit)ctx).Distance > 15f,
                                 new PrioritySelector(
                                    new CastAtLocation(SNOPower.Barbarian_Leap, ctx => ((DiaUnit)ctx).Position),
                                    new CastOnUnit(SNOPower.Barbarian_FuriousCharge, ctx => ((DiaUnit)ctx).ACDGuid),
                                    new CastOnUnit(SNOPower.Barbarian_AncientSpear, ctx => ((DiaUnit)ctx).ACDGuid),
                                    CommonBehaviors.MoveTo(ctx => ((DiaUnit)ctx).Position, "Moving towards unit")
                                )
                            ),

                            new SelfCast(SNOPower.Barbarian_BattleRage,
                                require => !ZetaDia.Me.HasBuff(SNOPower.Barbarian_BattleRage)
                            ),

                            new SelfCast(SNOPower.Barbarian_Revenge, ctx => ((DiaUnit)ctx).Distance < 12f),

                            // Buff attack rate!
                            new SelfCast(SNOPower.Barbarian_WrathOfTheBerserker,
                                ctx => (Clusters.GetClusterCount(ZetaDia.Me, CombatTargeting.Instance.LastObjects, ClusterType.Radius, 12f) >= 
                                    BelphegorSettings.Instance.Barbarain.RageSkillsAoeCount || 
                                    Unit.IsElite((DiaUnit)ctx, 15f) && !ZetaDia.Me.HasBuff(SNOPower.Barbarian_WrathOfTheBerserker))
                            ),
                            new SelfCast(SNOPower.Barbarian_CallOfTheAncients,
                                ctx => Clusters.GetClusterCount(ZetaDia.Me, CombatTargeting.Instance.LastObjects, ClusterType.Radius, 12f) >= 
                                    BelphegorSettings.Instance.Barbarain.RageSkillsAoeCount || 
                                    Unit.IsElite((DiaUnit)ctx, 15f)
                            ),

                            // AOE
                            new SelfCast(SNOPower.Barbarian_Earthquake,
                                ctx => ZetaDia.Me.HitpointsCurrentPct <= 0.25 || Clusters.GetClusterCount(ZetaDia.Me, CombatTargeting.Instance.LastObjects, ClusterType.Radius, 12f) >= 
                                    BelphegorSettings.Instance.Barbarain.RageSkillsAoeCount
                                    || (Unit.IsElite((DiaUnit)ctx, 16f))
                            ),
                            new SelfCast(SNOPower.Barbarian_GroundStomp,
                                extra => Clusters.GetClusterCount(ZetaDia.Me, CombatTargeting.Instance.LastObjects, ClusterType.Radius, 12f) >= 2
                            ),
                            new SelfCast(SNOPower.Barbarian_Overpower,
                                ctx => Clusters.GetClusterCount(ZetaDia.Me, CombatTargeting.Instance.LastObjects, ClusterType.Radius, 12f) >= 2 ||
                                    Unit.IsElite((DiaUnit)ctx, 18f)
                            ),


                            // Threatning shout.
                            new SelfCast(SNOPower.Barbarian_ThreateningShout,
                                ctx => Clusters.GetClusterCount(ZetaDia.Me, CombatTargeting.Instance.LastObjects, ClusterType.Radius, 25f) >= 2 ||
                                    Unit.IsElite((DiaUnit)ctx, 16f)
                            ),

                            // Fury spenders.
                            new CastOnUnit(SNOPower.Barbarian_HammerOfTheAncients, ctx => ((DiaUnit)ctx).ACDGuid),

                            new Decorator(ctx => _rendTimer.IsFinished && PowerManager.CanCast(SNOPower.Barbarian_Rend) &&
                                    (Clusters.GetClusterCount(ZetaDia.Me, CombatTargeting.Instance.LastObjects, ClusterType.Radius, 18f) >= 2 ||
                                    (Unit.IsElite((DiaUnit)ctx, 18f))),
                                new Sequence(
                                    new CastOnUnit(SNOPower.Barbarian_Rend, ctx => ((DiaUnit)ctx).ACDGuid),
                                    new Action(ret => _rendTimer.Reset()))),

                            new CastAtLocation(SNOPower.Barbarian_SeismicSlam, ctx => ((DiaUnit)ctx).Position),
                            new CastOnUnit(SNOPower.Barbarian_WeaponThrow, ctx => ((DiaUnit)ctx).ACDGuid),

                            // Fury Generators
                            new CastOnUnit(SNOPower.Barbarian_Cleave, ctx => ((DiaUnit)ctx).ACDGuid),
                            new CastOnUnit(SNOPower.Barbarian_Bash, ctx => ((DiaUnit)ctx).ACDGuid),
                            new CastOnUnit(SNOPower.Barbarian_Frenzy, ctx => ((DiaUnit)ctx).ACDGuid)
                        )
                    ),

                    new Action(ret => RunStatus.Success)
                    );
        }

        #region timmers
        static Barbarian()
        {
            GameEvents.OnGameLeft += OnGameLeft;
            GameEvents.OnPlayerDied += OnGameLeft;
        }

        private static WaitTimer _sprintTimer = new WaitTimer(TimeSpan.FromSeconds(3));
        private static WaitTimer _rendTimer = new WaitTimer(TimeSpan.FromSeconds(3));

        static void OnGameLeft(object sender, EventArgs e)
        {
            _sprintTimer.Stop();
            _rendTimer.Stop();
        }
        #endregion


        public static void BarbarianOnLevelUp(object sender, EventArgs e)
        {
            if (ZetaDia.Me.ActorClass != ActorClass.Barbarian)
                return;

            int myLevel = ZetaDia.Me.Level;

            Logger.Write("Player leveled up, congrats! Your level is now: {0}",
                myLevel
                );

            #region Primarey Slot
                if (myLevel == 18)
                {
                    Logger.Write("Add [R] Ravage to Cleave");
                    ZetaDia.Me.SetActiveSkill(SNOPower.Barbarian_Cleave, 2, 0);
                }
                else if (myLevel == 9)
                {
                    Logger.Write("Add [R] Rupture to Cleave");
                    ZetaDia.Me.SetActiveSkill(SNOPower.Barbarian_Cleave, 1, 0);
                }
                else if (myLevel == 3)
                {
                    Logger.Write("Equip Cleave");
                    ZetaDia.Me.SetActiveSkill(SNOPower.Barbarian_Cleave, -1, 0);
                }
            #endregion

            #region Secondary Slot
                if (myLevel == 19)
                {
                    Logger.Write("Add [R] Blood Lust to Rend. ");
                    ZetaDia.Me.SetActiveSkill(SNOPower.Barbarian_Rend, 2, 1);
                }
                else if (myLevel == 11)
                {
                    Logger.Write("Equip Rend with [R] Ravage in the place of Hammer of the Ancients.");
                    ZetaDia.Me.SetActiveSkill(SNOPower.Barbarian_Rend, 1, 1);
                }
                else if (myLevel == 7)
                {
                    Logger.Write("Add [R] Rolling Thunder to Hammer of the Ancients.");
                    ZetaDia.Me.SetActiveSkill(SNOPower.Barbarian_HammerOfTheAncients, 1, 1);
                }
                else if (myLevel == 2)
                {
                    Logger.Write("Setting Hammer of the Ancients");
                    ZetaDia.Me.SetActiveSkill(SNOPower.Barbarian_HammerOfTheAncients, -1, 1);
                }
            #endregion

            #region Defencive Slot
                if (myLevel == 27)
                {
                    Logger.Write("Add [R] Battering Ram to Furious Charge. ");
                    ZetaDia.Me.SetActiveSkill(SNOPower.Barbarian_FuriousCharge, 1, 2);
                }
                else if (myLevel == 21)
                {
                    Logger.Write("Equip Furious Charge in the place of Leap.");
                    ZetaDia.Me.SetActiveSkill(SNOPower.Barbarian_FuriousCharge, -1, 2);
                }
                else if (myLevel == 14)
                {
                    Logger.Write("Add [R] Iron Impact to Leap.");
                    ZetaDia.Me.SetActiveSkill(SNOPower.Barbarian_Leap, -1, 2);
                }
                else if (myLevel == 8)
                {
                    Logger.Write("Equip Leap in the place of Ground Stomp.");
                    ZetaDia.Me.SetActiveSkill(SNOPower.Barbarian_Leap, -1, 2);
                }
                else if (myLevel == 4)
                {
                    Logger.Write("Setting Ground Stomp");
                    ZetaDia.Me.SetActiveSkill(SNOPower.Barbarian_GroundStomp, -1, 2);
                }
            #endregion

            #region Might Slot
                if (myLevel == 26)
                {
                    Logger.Write("Add [R] Marauder's Rage to Battle Rage. ");
                    ZetaDia.Me.SetActiveSkill(SNOPower.Barbarian_BattleRage, 1, 3);
                }
                else if (myLevel == 22)
                {
                    Logger.Write("Equip Battle Rage in the place of Threatening Shout.");
                    ZetaDia.Me.SetActiveSkill(SNOPower.Barbarian_BattleRage, -1, 3);
                }
                else if (myLevel == 17)
                {
                    Logger.Write("Equip Threatening Shout in the place of Ground Stomp.");
                    ZetaDia.Me.SetActiveSkill(SNOPower.Barbarian_ThreateningShout, -1, 3);
                }
                else if (myLevel == 12)
                {
                    Logger.Write("Add [R] Deafening Crash to Ground Stomp.");
                    ZetaDia.Me.SetActiveSkill(SNOPower.Barbarian_GroundStomp, 1, 3);
                }
                else if (myLevel == 9)
                {
                    Logger.Write("Equip Ground Stomp.");
                    ZetaDia.Me.SetActiveSkill(SNOPower.Barbarian_GroundStomp, -1, 3);
                }
            #endregion

            #region Tactics Slot
                if (myLevel == 19)
                {
                    Logger.Write("Add [R] Vengeance Is Mine to Revenge. ");
                    ZetaDia.Me.SetActiveSkill(SNOPower.Barbarian_Revenge, 1, 4);
                }
                if (myLevel == 14)
                {
                    Logger.Write("Equip Revenge. ");
                    ZetaDia.Me.SetActiveSkill(SNOPower.Barbarian_Revenge, -1, 4);
                }
            #endregion

            #region Rage Slot
                if (myLevel == 29)
                {
                    Logger.Write("Add [R] Storm of Steel to Overpower.");
                    ZetaDia.Me.SetActiveSkill(SNOPower.Barbarian_Overpower, 1, 5);
                }
                else if (myLevel == 26)
                {
                    Logger.Write("Equip Overpower in the place of Earthquake.");
                    ZetaDia.Me.SetActiveSkill(SNOPower.Barbarian_Overpower, -1, 5);
                }
                else if (myLevel == 24)
                {
                    Logger.Write("Add [R] Giant's Stride to Earthquake.");
                    ZetaDia.Me.SetActiveSkill(SNOPower.Barbarian_Earthquake, 1, 5);
                }
                else if (myLevel == 19)
                {
                    Logger.Write("Equip Earthquake.");
                    ZetaDia.Me.SetActiveSkill(SNOPower.Barbarian_Earthquake, -1, 5);
                }
            #endregion

            #region Passive Skills
                if (myLevel == 30)
                {
                    Logger.Write("Equip [P] Bloodthirst.");
                    ZetaDia.Me.SetTraits(SNOPower.Barbarian_Passive_WeaponsMaster, SNOPower.Barbarian_Passive_InspiringPresence, SNOPower.Barbarian_Passive_Bloodthirst);
                }
                if (myLevel == 20)
                {
                    Logger.Write("Equip [P] Inspiring Presence.");
                    ZetaDia.Me.SetTraits(SNOPower.Barbarian_Passive_WeaponsMaster, SNOPower.Barbarian_Passive_InspiringPresence);
                }
                else if (myLevel == 16)
                {
                    Logger.Write("Equip [P] Weapons Master in the place of [P] Ruthless.");
                    ZetaDia.Me.SetTraits(SNOPower.Barbarian_Passive_WeaponsMaster);
                }
                else if (myLevel == 10)
                {
                    Logger.Write("Equip [P] Ruthless.");
                    ZetaDia.Me.SetTraits(SNOPower.Barbarian_Passive_Ruthless);
                }
            #endregion
        }
    }
}
